
Public MustInherit Class SortedKeyedCollectionWithEvents(Of KeyType, itemType)
    Inherits SortedList
End Class

<Serializable(), ObfuscationAttribute(Exclude:=True, ApplyToMembers:=True)> _
Public MustInherit Class KeyedCollectionWithEvents(Of keyType, itemType)
    Inherits ObjectModel.KeyedCollection(Of keyType, itemType)
    Implements IBindingList, Runtime.Serialization.ISerializable

    Public Event BeforeInsert As EventHandler(Of KeyedCollectionWithEventsArgs(Of itemType))
    Public Event AfterInsert As EventHandler(Of KeyedCollectionWithEventsArgs(Of itemType))
    Public Event BeforeRemove As EventHandler(Of KeyedCollectionWithEventsArgs(Of itemType))
    Public Event AfterRemove As EventHandler(Of KeyedCollectionWithEventsArgs(Of itemType))
    Public Event AfterSet As EventHandler(Of KeyedCollectionWithEventsArgs(Of itemType))
    Public Event BeforeClear As EventHandler
    Public Event AfterClear As EventHandler

    <NonSerialized()> _
    Private mIndex As PropertyDescriptor = Nothing

    Protected Overrides Sub ClearItems()
        RaiseEvent BeforeClear(Me, Nothing)
        MyBase.ClearItems()
        RaiseEvent ListChanged(Me, New ListChangedEventArgs(ListChangedType.Reset, 0))
        RaiseEvent AfterClear(Me, Nothing)
    End Sub
    Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As itemType)
        RaiseEvent BeforeInsert(Me, New KeyedCollectionWithEventsArgs(Of itemType)(index, item))
        MyBase.InsertItem(index, item)
        RaiseEvent ListChanged(Me, New ListChangedEventArgs(ListChangedType.ItemAdded, index))
        RaiseEvent AfterInsert(Me, New KeyedCollectionWithEventsArgs(Of itemType)(index, item))
    End Sub
    Protected Overrides Sub RemoveItem(ByVal index As Integer)
        Dim value As itemType = Me.Items(index)
        RaiseEvent BeforeRemove(Me, New KeyedCollectionWithEventsArgs(Of itemType)(index, value))
        MyBase.RemoveItem(index)
        RaiseEvent ListChanged(Me, New ListChangedEventArgs(ListChangedType.ItemDeleted, index))
        RaiseEvent AfterRemove(Me, New KeyedCollectionWithEventsArgs(Of itemType)(index, value))
    End Sub
    Protected Overrides Sub SetItem(ByVal index As Integer, ByVal item As itemType)
        MyBase.SetItem(index, item)
        RaiseEvent ListChanged(Me, New ListChangedEventArgs(ListChangedType.ItemChanged, index))
        RaiseEvent AfterSet(Me, New KeyedCollectionWithEventsArgs(Of itemType)(index))
    End Sub

    Public Function Sort(ByVal Sorted As KeyedCollectionWithEvents(Of keyType, itemType)) As KeyedCollectionWithEvents(Of keyType, itemType)
        If Not GetType(itemType).GetInterface("IComparable", False) Is Nothing Then
            If Sorted Is Nothing Then
                Dim tmp As itemType
                For i As Integer = 0 To Me.Count - 1

                    For b As Integer = 0 To Me.Count - 2
                        If CType(Me(b), IComparable).CompareTo(Me(b + 1)) < 0 Then
                            'swap them around
                            tmp = Me(b + 1)
                            Me.RemoveAt(b + 1)
                            Me.Insert(b, tmp)
                        End If

                    Next
                Next

            Else
                If Me.Count > 0 Then
                    ' always add the first item
                    Sorted.Add(Me.Items(0))

                    For i As Integer = 1 To Me.Count - 1
                        For s As Integer = 0 To Sorted.Count - 1
                            If CType(Sorted(s), IComparable).CompareTo(Me(i)) < 0 Then
                                ' Insert sorted
                                Sorted.Insert(s, Me(i))
                                Exit For
                            ElseIf s = Sorted.Count - 1 Then
                                ' Insert it at the end if not found already
                                Sorted.Add(Me(i))
                                'sortedList.Insert(s, Me(i))
                            End If
                        Next
                    Next
                End If
            End If
            Return Sorted
        Else
            Throw New NotSupportedException()

            Return Nothing
        End If
    End Function

    Public Sub AddIndex(ByVal [property] As System.ComponentModel.PropertyDescriptor) Implements System.ComponentModel.IBindingList.AddIndex
        'mIndex = [property]
        Throw New NotSupportedException()
    End Sub

    Public Function AddNew() As Object Implements System.ComponentModel.IBindingList.AddNew
        Throw New NotSupportedException()
    End Function

    Public ReadOnly Property AllowEdit() As Boolean Implements System.ComponentModel.IBindingList.AllowEdit
        Get
            Return True
        End Get
    End Property

    Public ReadOnly Property AllowNew() As Boolean Implements System.ComponentModel.IBindingList.AllowNew
        Get
            Return False
        End Get
    End Property

    Public ReadOnly Property AllowRemove() As Boolean Implements System.ComponentModel.IBindingList.AllowRemove
        Get
            Return False
        End Get
    End Property

    Public Sub ApplySort(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal direction As System.ComponentModel.ListSortDirection) Implements System.ComponentModel.IBindingList.ApplySort
        Throw New NotSupportedException()
    End Sub

    Public Function Find(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal key As Object) As Integer Implements System.ComponentModel.IBindingList.Find
        Throw New NotSupportedException()
    End Function

    Public ReadOnly Property IsSorted() As Boolean Implements System.ComponentModel.IBindingList.IsSorted
        Get
            Return True
        End Get
    End Property

    Public Event ListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs) Implements System.ComponentModel.IBindingList.ListChanged

    Public Sub RemoveIndex(ByVal [property] As System.ComponentModel.PropertyDescriptor) Implements System.ComponentModel.IBindingList.RemoveIndex
        Throw New NotSupportedException()
    End Sub

    Public Sub RemoveSort() Implements System.ComponentModel.IBindingList.RemoveSort
        Throw New NotSupportedException()
    End Sub

    Public ReadOnly Property SortDirection() As System.ComponentModel.ListSortDirection Implements System.ComponentModel.IBindingList.SortDirection
        Get
            Throw New NotSupportedException()
        End Get
    End Property

    Public ReadOnly Property SortProperty() As System.ComponentModel.PropertyDescriptor Implements System.ComponentModel.IBindingList.SortProperty
        Get
            Throw New NotSupportedException()
        End Get
    End Property

    Public ReadOnly Property SupportsChangeNotification() As Boolean Implements System.ComponentModel.IBindingList.SupportsChangeNotification
        Get
            Return True
        End Get
    End Property

    Public ReadOnly Property SupportsSearching() As Boolean Implements System.ComponentModel.IBindingList.SupportsSearching
        Get
            Return False
        End Get
    End Property

    Public ReadOnly Property SupportsSorting() As Boolean Implements System.ComponentModel.IBindingList.SupportsSorting
        Get
            Return False
        End Get
    End Property

#Region "Serialization Functions"
    Public Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData
        info.AddValue("collection", Me.Items, GetType(System.Collections.Generic.List(Of itemType)))
        GetObjectDataAdditionalSerialization(info, context)
    End Sub
    Public MustOverride Sub GetObjectDataAdditionalSerialization(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext)

    Protected Sub New(ByVal Info As Runtime.Serialization.SerializationInfo, ByVal context As Runtime.Serialization.StreamingContext)
        MyBase.New()
        For Each item As itemType In Info.GetValue("collection", GetType(System.Collections.Generic.List(Of itemType)))
            Me.Add(item)
        Next

        NewAdditionalDeserialization(Info, context)
    End Sub
    Public MustOverride Sub NewAdditionalDeserialization(ByVal Info As Runtime.Serialization.SerializationInfo, ByVal context As Runtime.Serialization.StreamingContext)


    Sub New()
        MyBase.New()
    End Sub

#End Region
End Class

<Serializable(), ObfuscationAttribute(Exclude:=True, ApplyToMembers:=True)> _
Public Class KeyedCollectionWithEventsArgs(Of itemType)
    Inherits System.EventArgs

    Private mIndex As Integer
    Private mItem As itemType = Nothing

    Sub New(ByVal Index As Integer)
        mIndex = Index
    End Sub
    Sub New(ByVal Index As Integer, ByVal Item As itemType)
        mIndex = Index
        mItem = Item
    End Sub

    Public ReadOnly Property Item() As itemType
        Get
            Return mItem
        End Get
    End Property

    Public ReadOnly Property Index() As Integer
        Get
            Return mIndex
        End Get
    End Property
End Class
